2157. Sum

 

Roman’s parents gave him an undirected, connected, weighted graph with n vertices and n – 1 edges. Roman wants to find the total length of all paths between every pair of vertices in the graph. The length of a path is defined as the sum of the weights of the edges it includes. Since the path from vertex u to vertex v is the same as the path from v to u, Roman treats them as a single path and does not distinguish between them.

 

Input. The first line contains an integer n (2 ≤ n ≤ 105) – the number of vertices in the graph.

Each of the next n – 1 lines describes an edge and contains three integers: the numbers of the two vertices connected by the edge (vertices are numbered from 1 to n), and the weight of the edge.

 

Output. Print the total length of all distinct paths between all pairs of vertices, modulo 109.

 

Sample input 1

Sample output 1

3

1 2 1

1 3 3

8

 

 

Sample input 2

Sample output 2

6

1 2 5

1 3 1

2 4 2

2 5 4

2 6 3

90

 

In the first example, all the paths in the tree are as follows: 1 – 2, 1 – 3, and 2 – 1 – 3. Their lengths are 1, 3, and 4 respectively, and the sum of these lengths is 1 + 3 + 4 = 8.

 

 

SOLUTION

graphs, depth first search, tree

 

Algorithm analysis

Perform a depth-first search starting from an arbitrary vertex of the tree. Consider an edge (u, v) with weight w. Let the number of vertices in the subtree rooted at v be c. Then, there are c vertices on one side of the edge and nc vertices on the other side. The edge (u, v) is included in c * (nc) distinct paths between pairs of vertices. Therefore, its contribution to the total length of all paths is c * (nc) * w. We just need to iterate over all edges using depth-first search and sum up their contributions to the overall path length.

 

 

Example

The graphs given in the examples have the following structure:

 

Consider the contribution of the edges to the total length of all paths in the first example.

The edge (1, 2) with weight 1 belongs to two paths:

·        1 – 2;

·        2 – 1 – 3;

Its contribution to the total sum is 1 * 2 * 1 = 2.

The edge (1, 3) with weight 3 belongs to two paths:

·        1 – 3;

·        2 – 1 – 3;

Its contribution to the total sum is 2 * 1 * 3 = 6.

The total length of all paths is 2 + 6 = 8.

 

In the second example, let us consider the contribution of the edge (1, 2) with weight 5 to the total length of all paths.

 

The number of vertices in the subtree rooted at vertex 2 is c = 4 (including vertex 2 itself). Then, on the other side of the edge (1, 2) there are nc = 6 – 4 = 2 vertices. Therefore, the number of distinct paths passing through the edge (1, 2) is c * (nc) = 4 * 2 = 8.

Indeed, these are all pairs of vertices where one lies in the subtree of vertex 2, and the other lies outside of it:

1 – 2, 1 – 2 – 4, 1 – 2 – 5, 1 – 2 – 6,

3 – 1 – 2, 3 – 1 – 2 – 4, 3 – 1 – 2 – 5, 3 – 1 – 2 – 6

The contribution of the edge (1, 2) with weight 5 to the total length of all paths is

c * (nc) * w = 4 * 2 * 5 = 40

 

Algorithm implementation

Declare the value of the modulo as MOD.

 

#define MOD 1000000000

 

The input weighted graph is stored in an adjacency list g.

 

vector<vector<pair<int,int> > > g;

 

The function dfs performs a depth-first search starting from vertex v and returns the number of vertices in the subtree rooted at v (including v itself). The number of such vertices is counted in the variable cnt. Initially, set cnt = 1 since the subtree already includes vertex v.

 

int dfs(int v, int p = -1)

{

  int cnt = 1;

  for (auto edge : g[v])

  {

    int to = edge.first;

    int w = edge.second;

 

Consider the edge (v, to) with weight w. Let c be the number of vertices in the subtree rooted at vertex to. Then, one side of the edge contains c vertices, and the other side contains nc vertices. The edge (v, to) is included in c * (nc) different paths between pairs of vertices. Thus, the contribution of the edge (v, to) to the total length of all paths is

c * (nc) * w

 

    if (to != p)

    {

      int c = dfs(to, v);

      res = (res + 1LL * c * (n - c) * w) % MOD;

      cnt += c;

    }

  }

  return cnt;

}

 

The main part of the program. Read the input weighted graph into the adjacency list g.

 

scanf("%d", &n);

g.resize(n + 1);

for(i = 1; i < n; i++)

{

  scanf("%d %d %d", &u, &v, &d);

  g[u].push_back({v, d});

  g[v].push_back({u, d});

}

 

Start a depth-first search from vertex 1. The vertices of the graph are numbered from 1 to n.

 

dfs(1);

 

Print the answer.

 

printf("%lld\n",res);

 

Java implementation

 

import java.util.*;

import java.io.*;

 

class Edge

{

  int to;

  int weight;

  public Edge(int to, int weight)

  {

    this.to = to;

    this.weight = weight;

  }

}

 

public class Main

{

  static int MOD = 1000000000;

  static ArrayList<Edge>[] g;    

  static int n, m;

  static long res;

 

  static int dfs(int v, int p)

  {

    int cnt = 1;

    for(Edge edge : g[v])

    {

      int to = edge.to;

      int w = edge.weight;

      if (to != p)

      {

        int c = dfs(to, v);

        res = (res + 1L * c * (n - c) * w) % MOD;

        cnt += c;

      }

    }

    return cnt;

  }

 

  public static void main(String[] args)

  {

    FastScanner con = new FastScanner(System.in);

    n = con.nextInt();

    g = new ArrayList[n+1]; // unchecked

 

    for (int i = 0; i <= n; i++)

      g[i] = new ArrayList<Edge>();

 

    for (int i = 1; i < n; i++)

    {

      int u = con.nextInt();

      int v = con.nextInt();

      int d = con.nextInt();

      g[u].add(new Edge(v,d));

      g[v].add(new Edge(u,d));

    }

   

    dfs(1,-1);

    System.out.println(res);   

  }

}  

 

class FastScanner

{

  BufferedReader br;

  StringTokenizer st;

 

  public FastScanner(InputStream inputStream)

  {

    br = new BufferedReader(new InputStreamReader(inputStream));

    st = new StringTokenizer("");

  }

 

  public String next()

  {

    while (!st.hasMoreTokens())

    {

      try

      {

        st = new StringTokenizer(br.readLine());

      } catch (Exception e)

      {

        return null;

      }

    }

    return st.nextToken();

  }

 

  public int nextInt()

  {

    return Integer.parseInt(next());

  }

}

 

Python implementation

Declare the value of the modulo as MOD.

 

MOD = 1000000000

 

The function dfs performs a depth-first search starting from vertex v and returns the number of vertices in the subtree rooted at v (including v itself). The number of such vertices is counted in the variable cnt. Initially, set cnt = 1 since the subtree already includes vertex v.

 

def dfs(v, p = -1):

  global res

  cnt = 1

  for to, w in g[v]:

 

Consider the edge (v, to) with weight w. Let c be the number of vertices in the subtree rooted at vertex to. Then, one side of the edge contains c vertices, and the other side contains nc vertices. The edge (v, to) is included in c * (nc) different paths between pairs of vertices. Thus, the contribution of the edge (v, to) to the total length of all paths is

c * (nc) * w

 

    if to != p:

      c = dfs(to, v)

      res = (res + c * (n - c) * w) % MOD

      cnt += c

  return cnt

 

The main part of the program. Read the input data.

 

n = int(input())

g = [[] for _ in range(n + 1)]

res = 0

 

for _ in range(n - 1):

  u, v, d = map(int, input().split())

  g[u].append((v, d))

  g[v].append((u, d))

 

Start a depth-first search from vertex 1. The vertices of the graph are numbered from 1 to n.

 

dfs(1)

 

Print the answer.

 

print(res)